package com.mofum.msdom.excel.annotation.parser.impl;

import com.mofum.msdom.excel.annotation.ATColumn;
import com.mofum.msdom.excel.annotation.ATSheetColumnIndex;
import com.mofum.msdom.excel.annotation.ATStyle;
import com.mofum.msdom.excel.annotation.parser.AnnotationParser;
import com.mofum.msdom.excel.metadata.MPColumn;
import com.mofum.msdom.excel.metadata.MPSheetColumnIndex;
import com.mofum.msdom.excel.metadata.MPStyle;
import com.mofum.msdom.excel.utils.ReflectUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * AT 列名注解解析器
 *
 * @author 1615690513@qq.com
 * @since 2018/11/21 0021 13:11
 */
public class ATColumnParser<T> implements AnnotationParser<T, MPColumn> {

    public Map<Field, MPColumn> parseField(T o) {

        Map<Field, MPColumn> map = new HashMap<Field, MPColumn>();

        Field[] fields = ReflectUtils.convertToClass(o).getDeclaredFields();

        for (Field field : fields) {

            if (field.isAnnotationPresent(ATColumn.class)) {

                ATColumn atColumn = field.getAnnotation(ATColumn.class);

                map.put(field, parse(atColumn));

            }

        }

        return map;
    }

    public Map<Type, MPColumn> parseType(T o) {

        Map<Type, MPColumn> map = new HashMap<Type, MPColumn>();

        Class<T> clazz = ReflectUtils.convertToClass(o);

        if (clazz.isAnnotationPresent(ATColumn.class)) {

            ATColumn atColumn = clazz.getAnnotation(ATColumn.class);

            map.put(clazz, parse(atColumn));

        }

        return map;
    }

    public Map<Method, MPColumn> parseMethod(T o) {

        Map<Method, MPColumn> map = new HashMap<Method, MPColumn>();

        Method[] methods = ReflectUtils.convertToClass(o).getDeclaredMethods();

        for (Method method : methods) {

            if (method.isAnnotationPresent(ATColumn.class)) {

                ATColumn atColumn = method.getAnnotation(ATColumn.class);

                map.put(method, parse(atColumn));

            }

        }

        return map;
    }

    public Map<Method, List<MPColumn>> parseParams(T o) {

        Map<Method, List<MPColumn>> map = new HashMap<Method, List<MPColumn>>();

        Method[] methods = ReflectUtils.convertToClass(o).getMethods();

        for (Method method : methods) {

            List<MPColumn> list = new ArrayList<MPColumn>();

            Annotation[][] parameterAnnotations = method.getParameterAnnotations();

            for (Annotation[] parameterAnnotation : parameterAnnotations) {
                for (Annotation annotation : parameterAnnotation) {
                    if (annotation instanceof ATColumn) {
                        ATColumn atColumn = (ATColumn) annotation;
                        list.add(parse(atColumn));
                    }
                }
            }

            map.put(method, list);
        }

        return map;
    }

    public MPColumn parse(ATColumn atColumn) {
        MPColumn mpColumn = new MPColumn();
        mpColumn.setIndex(atColumn.index());
        mpColumn.setFormat(atColumn.format());
        mpColumn.setConverter(atColumn.converter());
        mpColumn.setExcelConverter(atColumn.excelConverter());
        mpColumn.setWidth(atColumn.width());
        mpColumn.setRequired(atColumn.required());
        mpColumn.setValidator(atColumn.validator());

        //工作表格列索引
        ATSheetColumnIndexParser<MPSheetColumnIndex> sheetColumnIndexParser = new ATSheetColumnIndexParser<>();
        List<MPSheetColumnIndex> sheetColumnIndices = new ArrayList<MPSheetColumnIndex>();
        for (ATSheetColumnIndex sheetColumnIndex : atColumn.indexes()) {
            sheetColumnIndices.add(sheetColumnIndexParser.parse(sheetColumnIndex));
        }
        mpColumn.setIndexes(sheetColumnIndices.toArray(new MPSheetColumnIndex[]{}));

        //样式
        ATStyleParser<MPStyle> parser = new ATStyleParser();
        List<MPStyle> list = new ArrayList<MPStyle>();
        for (ATStyle atStyle : atColumn.styles()) {
            list.add(parser.parse(atStyle));
        }
        mpColumn.setStyles(list.toArray(new MPStyle[]{}));
        return mpColumn;
    }
}
